#include "MultiClassSVM.h"
//#include <stdlib.h>
//#include <string.h>

#ifdef WIN32
#include "MemoryOperators.h"
#endif
void MultiClassSVM::ReadData(char *strPath, int numOfClass, int numOfVector, int dimensionOfVec, double sigma, double C, char* strOutputPath)
{
	//init var
	strcpy(m_strPath, strPath);
	m_numOfClass = numOfClass;
	m_numOfVector = numOfVector;
	m_dimensionOfVec = dimensionOfVec;
	m_sigma = sigma; 
	m_C = C;
	//end init var
	
	Stroke stroke_tmp;
	m_arrayVec = new CTrainVector* [m_numOfClass];
	for (int i = 0; i < m_numOfClass; ++i)
	{
		m_arrayVec[i] = new CTrainVector[m_numOfVector];
	}
	char tmp[203];
	for (int i = 1; i <= m_numOfVector; i++)
	{
		char buff[3];
		char buff_zeroDigit[2];
		strcpy(buff_zeroDigit, "");
		itoa(i, buff, 10);
		strcpy(tmp, m_strPath);
		strcat(tmp, "/s");
		if (strlen(buff)==1)
		{
			strcpy(buff_zeroDigit, "00");
		}
		else if (strlen(buff)==2)
		{
			strcpy(buff_zeroDigit, "0");
		}
		strcat(tmp, buff_zeroDigit);
		strcat(tmp, buff);
		strcat(tmp, "/s");
		strcat(tmp, buff_zeroDigit);
		strcat(tmp, buff);
		strcat(tmp, "d");
		char bufftmp[203];
		
		for (int j = 1; j <= m_numOfClass; j++)
		{
			strcpy(bufftmp, tmp);
			itoa(j, buff, 10);
			if(strlen(buff) == 1)
			{
				strcat(bufftmp, "0");
			}
			strcat(bufftmp, buff);
			strcat(bufftmp, ".dat");
			stroke_tmp.ReadFile(bufftmp);
			
			m_arrayVec[j-1][i-1].m_arrayFloat = stroke_tmp.featureExtraction(m_dimensionOfVec);
			m_arrayVec[j-1][i-1].m_LenOfArray = 2 * m_dimensionOfVec;
			//break;
			printf("extract feature %s\n", bufftmp);
		}
		//break;
		
	}
	printf("\n---------test-----------");
	//for (int i = 0; i < 24; i++)
	//{
	//	printf("%.2f\n", m_arrayVec[0][0].m_arrayFloat[i]);
	//}
	SaveData(strOutputPath);
	// LoadData("dataDigit.bin");
}
void MultiClassSVM::SaveData(char *strOutPath)
{
	FILE * pFile;
	pFile = fopen ( strOutPath , "wb" );
	fwrite (&m_numOfClass , sizeof(m_numOfClass), 1, pFile);
	fwrite (&m_numOfVector , sizeof(m_numOfVector), 1, pFile);
	fwrite (&m_dimensionOfVec , sizeof(m_dimensionOfVec), 1, pFile);
	for (int i = 0; i < m_numOfClass; ++i)
	{
		for (int j = 0; j < m_numOfVector; ++j)
		{
			fwrite(m_arrayVec[i][j].m_arrayFloat, sizeof(float), m_arrayVec[i][j].m_LenOfArray, pFile);
		}
	}
	fclose (pFile);
}
void MultiClassSVM::LoadAllData(char *strInputDataPath, char *strSVMDataPath)
{
	//FreeMemory();
	LoadData(strInputDataPath);
	LoadSVMParameter(strSVMDataPath);

}
void MultiClassSVM::LoadData(char *strInputPath)
{
	FILE * pFile;
	pFile = fopen ( strInputPath , "rb" );
	if (!pFile)
	{
		printf("cannot open file %s\n", strInputPath);
		return;
	}
	fread (&m_numOfClass , sizeof(m_numOfClass), 1, pFile);
	fread (&m_numOfVector , sizeof(m_numOfVector), 1, pFile);
	fread (&m_dimensionOfVec , sizeof(m_dimensionOfVec), 1, pFile);
	
	m_arrayVec = new CTrainVector* [m_numOfClass];
	for (int i = 0; i < m_numOfClass; ++i)
	{
		m_arrayVec[i] = new CTrainVector[m_numOfVector];
	}

	for (int i = 0; i < m_numOfClass; ++i)
	{
		for (int j = 0; j < m_numOfVector; ++j)
		{
			m_arrayVec[i][j].m_arrayFloat = new float[2 * m_dimensionOfVec];
			m_arrayVec[i][j].m_LenOfArray = 2 * m_dimensionOfVec;
			fread(m_arrayVec[i][j].m_arrayFloat, sizeof(float), m_arrayVec[i][j].m_LenOfArray, pFile);
		}
	}


	fclose (pFile);

}

void MultiClassSVM::SaveSVMParameter(char *strOutPath)
{
	FILE * pFile;
	pFile = fopen ( strOutPath , "wb" );
	fwrite (&m_numOfSVM , sizeof(m_numOfSVM), 1, pFile);
	for (int i = 0; i < m_numOfSVM; ++i)
	{
		m_svmData [i].SaveToFilePointer(pFile);
	}
	fclose (pFile);
}

void MultiClassSVM::LoadSVMParameter(char *strInputPath)
{
	//FreeMemory();
	m_svmData = new BinarySVM[m_numOfSVM];
	int i, j, count = 0;
	for (i = 0; i < m_numOfClass - 1; ++i)
	{
		for (j = i + 1; j < m_numOfClass; ++j)
		{
			m_svmData [count].InitData (m_arrayVec[i], m_numOfVector, m_arrayVec[j], m_numOfVector);
			
			//printf(" train data %d %d\n", i, j);
			//m_svmData [count].SMOTraining();
			count++;
		}
	}
	FILE * pFile;
	pFile = fopen ( strInputPath , "rb" );
	if (pFile == NULL)
	{
		printf("cannot open File %s\n", strInputPath);
		return;
	}
	fread (&m_numOfSVM , sizeof(m_numOfSVM), 1, pFile);
	
	for (i = 0; i < m_numOfSVM; ++i)
	{
		m_svmData [i].LoadFormFilePointer(pFile);
	}
	fclose (pFile);

	//m_numOfSVM = ( (m_numOfClass - 1) * m_numOfClass ) / 2;
	//m_svmData = new BinarySVM[m_numOfSVM];
	
}
void MultiClassSVM::TrainData(char *strOutputPath)
{
	printf("---- Begin train Data ---------\n");
	m_numOfSVM = ( (m_numOfClass - 1) * m_numOfClass ) / 2;
	m_svmData = new BinarySVM[m_numOfSVM];
	int i, j, count = 0;
	for (i = 0; i < m_numOfClass - 1; ++i)
	{
		for (j = i + 1; j < m_numOfClass; ++j)
		{
			m_svmData [count].Init (m_arrayVec[i], m_numOfVector, m_arrayVec[j], m_numOfVector, m_sigma, m_C );
			printf(" train data %d %d\n", i, j);
			m_svmData [count].SMOTraining();
			count++;
		}
	}
	printf ("---- finish train data----\n");
	
	printf("-----save data-----\n");
	//SaveData("dataDigit.bin");
	SaveSVMParameter(strOutputPath);
	printf("-----finish data-----\n");
	
	
}

int  MultiClassSVM::Classify(float *xVec, int n)
{
	int *ptmp = new int [m_numOfClass];
	int i, j, index;
	int tmp;
	memset(ptmp, 0, m_numOfClass * sizeof(int));
	for (i = 0; i < m_numOfClass - 1; ++i)
	{
		for (j = i + 1; j < m_numOfClass; ++j)
		{
			// int numtmp = m_numOfClass - 1;
			// sum = 0;
			// for (int k = 1; k < i; ++k)
			// {
				// sum += numtmp;
				// --numtmp;
			// }
			// sum = sum + (j - i);
			index = ( i * (2 * m_numOfClass - i - 3) )/ 2 + j;
			tmp = m_svmData[index].classify(xVec, n);
			ptmp[i] += tmp;
			ptmp[j] += (1 - tmp);
		}
	}
	
	int indexMax = 0;
	for (i = 1; i < m_numOfClass; ++i)
	{
		if (ptmp[i] > ptmp[indexMax])
			indexMax = i;
	}
	
	delete []ptmp;
	
	return indexMax;
}

void MultiClassSVM::FreeMemory()
{
	if (!m_arrayVec)
		return;
	int i, j;
	for (i = 0; i < m_numOfClass; ++i)
	{
		for (j = 0; j < m_numOfVector; ++j)
			delete[] m_arrayVec[i][j].m_arrayFloat;
		delete[] m_arrayVec[i];
	}
	
	delete[] m_arrayVec;
	m_arrayVec = 0;//NULL
	if (!m_svmData)
		return;
	for (i = 0; i < m_numOfSVM; ++i)
	{
		m_svmData[i].FreeMemory();
	}
	delete [] m_svmData;
	m_svmData = 0;
}